home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / pattern.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-13  |  12.4 KB  |  442 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: pattern.c,v 5.9 1993/05/14 03:53:46 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.9 $   $State: Exp $
  6.  *
  7.  *            Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: pattern.c,v $
  17.  * Revision 5.9  1993/05/14  03:53:46  syd
  18.  * Fix wrong message being displayed and then overwritten
  19.  * for long aliases.
  20.  * From: "Robert L. Howard" <robert.howard@matd.gatech.edu>
  21.  *
  22.  * Revision 5.8  1993/04/12  02:34:36  syd
  23.  * I have now added a parameter which controls whether want_to clears the
  24.  * line and centers the question or behaves like it did before. I also
  25.  * added a 0 at the end of the parameter list to all the other calls to
  26.  * want_to where a centered question on a clean line is not desirable.
  27.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  28.  *
  29.  * Revision 5.7  1993/02/03  19:06:31  syd
  30.  * Remove extra strchr/strcat/strcpy et al declarations
  31.  * From: Syd
  32.  *
  33.  * Revision 5.6  1993/01/19  05:10:13  syd
  34.  * There is a mismatch between the number of args and the format string in
  35.  * src/pattern.c.
  36.  * In nls/C/C/C/s_filter.m there is a , after OutOfMemory.
  37.  * This is my fault, and although it doesn't seem to affect things, there is no
  38.  * need for it.
  39.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  40.  *
  41.  * Revision 5.5  1992/12/25  00:30:37  syd
  42.  * change way message works
  43.  *
  44.  * Revision 5.4  1992/12/25  00:22:39  syd
  45.  * add missing *
  46.  * From: Syd
  47.  *
  48.  * Revision 5.3  1992/12/24  21:42:01  syd
  49.  * Fix messages and nls messages to match.  Plus use want_to
  50.  * where appropriate.
  51.  * From: Syd, via prompting from Jan Djarv <Jan.Djarv@sa.erisoft.se>
  52.  *
  53.  * Revision 5.2  1992/11/26  00:46:50  syd
  54.  * Fix how errno is used so err is inited and used instead
  55.  * as errno gets overwritten by print system call
  56.  * From: Syd
  57.  *
  58.  * Revision 5.1  1992/10/03  22:58:40  syd
  59.  * Initial checkin as of 2.4 Release at PL0
  60.  *
  61.  *
  62.  ******************************************************************************/
  63.  
  64. /**    General pattern matching for the ELM mailer.     
  65.  
  66. **/
  67.  
  68. #include <errno.h>
  69.  
  70. #include "headers.h"
  71. #include "s_elm.h"
  72.  
  73. static char pattern[SLEN] = { "" };
  74. static char alt_pattern[SLEN] = { "" };
  75.  
  76. extern int errno;
  77.  
  78. char *error_description(), *shift_lower();
  79. static char *tag_word = NULL;
  80. static char *tagged_word = NULL;
  81. static char *Tagged_word = NULL;
  82. static char *delete_word = NULL;
  83. static char *mark_delete_word = NULL;
  84. static char *Mark_delete_word = NULL;
  85. static char *undelete_word = NULL;
  86. static char *undeleted_word = NULL;
  87. static char *Undeleted_word = NULL;
  88. static char *enter_pattern = NULL;
  89. static char *match_pattern = NULL;
  90. static char *entire_match_pattern = NULL;
  91. static char *match_anywhere = NULL;
  92.  
  93. int
  94. meta_match(function)
  95. int function;
  96. {
  97.     char    ch, tagmsg[SLEN];
  98.  
  99.     /** Perform specific function based on whether an entered string 
  100.         matches either the From or Subject lines.. 
  101.         Return TRUE if the current message was matched, else FALSE.
  102.     **/
  103.  
  104.     register int i, tagged=0, count=0, curtag = 0;
  105.     char        msg[SLEN];
  106.     static char     meta_pattern[SLEN];
  107.  
  108.     if (delete_word == NULL) {
  109.          tag_word = catgets(elm_msg_cat, ElmSet, ElmTag, "Tag");
  110.          tagged_word = catgets(elm_msg_cat, ElmSet, ElmTagged, "tagged");
  111.          Tagged_word = catgets(elm_msg_cat, ElmSet, ElmCapTagged, "Tagged");
  112.          delete_word = catgets(elm_msg_cat, ElmSet, ElmDelete, "Delete");
  113.          mark_delete_word = catgets(elm_msg_cat, ElmSet, ElmMarkDelete, "marked for deletion");
  114.          Mark_delete_word = catgets(elm_msg_cat, ElmSet, ElmCapMarkDelete, "Marked for deletion");
  115.          undelete_word = catgets(elm_msg_cat, ElmSet, ElmUndelete, "Undelete");
  116.          undeleted_word = catgets(elm_msg_cat, ElmSet, ElmUndeleted, "undeleted");
  117.          Undeleted_word = catgets(elm_msg_cat, ElmSet, ElmCapUndeleted, "Undeleted");
  118.          enter_pattern = catgets(elm_msg_cat, ElmSet, ElmEnterPattern, "Enter pattern: ");
  119.     }
  120.  
  121.     PutLine2(LINES-3, strlen(Prompt), catgets(elm_msg_cat, ElmSet, ElmMessagesMatchPattern,
  122.          "%s %s that match pattern..."), 
  123.          function==TAGGED?tag_word: function==DELETED?delete_word:undelete_word, items);
  124.  
  125.     if (function == TAGGED) {    /* are messages already tagged??? */
  126.       for (i=0; i < message_count; i++)
  127.         if (ison(ifmain(headers[i]->status,
  128.                         aliases[i]->status),TAGGED))
  129.           tagged++;
  130.  
  131.       if (tagged) {
  132.         if (tagged > 1) {
  133.           MCsprintf(tagmsg, catgets(elm_msg_cat, ElmSet, ElmSomeMessagesATagged,
  134.         "Some %s are already tagged."), items);
  135.           MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmRemoveTags,
  136.         "%s Remove Tags? (%c/%c) "),
  137.         tagmsg, *def_ans_yes, *def_ans_no);
  138.         } else {
  139.           MCsprintf(tagmsg, catgets(elm_msg_cat, ElmSet, ElmAMessageATagged,
  140.         "One %s is already tagged."), item);
  141.           MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmRemoveTag,
  142.         "%s Remove Tag? (%c/%c) "),
  143.         tagmsg, *def_ans_yes, *def_ans_no);
  144.         }
  145.     
  146.         ch = want_to(msg, *def_ans_yes, LINES-2, 0);
  147.         if (ch != *def_ans_no) {    /* remove tags... */
  148.           for (i=0; i < message_count; i++) {
  149.             if (inalias)
  150.               clearit(aliases[i]->status,TAGGED);
  151.             else
  152.               clearit(headers[i]->status,TAGGED);
  153.         show_new_status(i);
  154.           }
  155.         }
  156.       }
  157.     }
  158.     
  159.     PutLine0(LINES-2,0, enter_pattern);
  160.     CleartoEOLN();
  161.  
  162.     optionally_enter(meta_pattern, LINES-2, strlen(enter_pattern),
  163.       FALSE, FALSE);
  164.  
  165.     if (strlen(meta_pattern) == 0) {
  166.       ClearLine(LINES-2);
  167.       return(curtag);
  168.     }
  169.  
  170.     strcpy(meta_pattern, shift_lower(meta_pattern));   /* lowercase it */
  171.  
  172.     if (inalias) {
  173.       for (i = 0; i < message_count; i++) {
  174.         if (name_matches(i, meta_pattern) ||
  175.             alias_matches(i, meta_pattern)) {
  176.           if (! selected || (selected && (aliases[i]->status & VISIBLE))) {
  177.             if (function == UNDELETE)
  178.               clearit(aliases[i]->status, DELETED);
  179.             else
  180.               if ((function == DELETED) && (aliases[i]->type & SYSTEM)) {
  181.                 if(i == current - 1) curtag--;
  182.                 count--;
  183.               }
  184.               else
  185.                 setit(aliases[i]->status, function);
  186.             show_new_status(i);
  187.             if(i == current - 1) curtag++;
  188.             count++;
  189.           }
  190.         }
  191.       }
  192.     }
  193.     else {
  194.       for (i = 0; i < message_count; i++) {
  195.         if (from_matches(i, meta_pattern) ||
  196.             subject_matches(i, meta_pattern)) {
  197.           if (! selected || (selected && headers[i]->status & VISIBLE)) {
  198.             if (function == UNDELETE)
  199.               clearit(headers[i]->status, DELETED);
  200.             else
  201.               setit(headers[i]->status, function);
  202.             show_new_status(i);
  203.             if(i == current - 1) curtag++;
  204.             count++;
  205.           }
  206.         }
  207.       }
  208.     }
  209.  
  210.     ClearLine(LINES-2);    /* remove "pattern: " prompt */
  211.     
  212.     if (count > 1) {
  213.       error3(catgets(elm_msg_cat, ElmSet, ElmTaggedMessages,
  214.         "%s %d %s."), 
  215.              function==TAGGED? Tagged_word : 
  216.            function==DELETED? Mark_delete_word : Undeleted_word,
  217.          count, items);
  218.     } else if (count == 1) {
  219.       error2(catgets(elm_msg_cat, ElmSet, ElmTaggedMessage,
  220.         "%s 1 %s."), 
  221.              function==TAGGED? Tagged_word : 
  222.            function==DELETED? Mark_delete_word : Undeleted_word, item);
  223.     } else {
  224.       error2(catgets(elm_msg_cat, ElmSet, ElmNoMatchesNoTags,
  225.         "No matches. No %s %s."), items,
  226.          function==TAGGED? tagged_word : 
  227.            function==DELETED? mark_delete_word: undeleted_word);
  228.     }
  229.  
  230.     return(curtag);
  231. }
  232.       
  233. int
  234. pattern_match()
  235. {
  236.     /** Get a pattern from the user and try to match it with the
  237.         from/subject lines being displayed.  If matched (ignoring
  238.         case), move current message pointer to that message, if
  239.         not, error and return ZERO **/
  240.  
  241.     register int i;
  242.  
  243.     char buffer[SLEN];
  244.     int anywhere = FALSE;
  245.     int matched;
  246.  
  247.     if (match_pattern == NULL) {
  248.       match_pattern = catgets(elm_msg_cat, ElmSet, ElmMatchPattern,
  249.         "Match pattern:");
  250.       entire_match_pattern = catgets(elm_msg_cat, ElmSet,
  251.         ElmMatchPatternInEntire, "Match pattern (in entire %s):");
  252.       match_anywhere = catgets(elm_msg_cat, ElmSet, ElmMatchAnywhere,
  253.         "/ = Match anywhere in %s.");
  254.     }
  255.  
  256.     MCsprintf(buffer, entire_match_pattern, item);
  257.  
  258.     PutLine1(LINES-3,40, match_anywhere, items);
  259.     
  260.     PutLine0(LINES-1,0, match_pattern);
  261.  
  262.     if (pattern_enter(pattern, alt_pattern, LINES-1,
  263.         strlen(match_pattern)+1, buffer)) {
  264.       if (strlen(alt_pattern) == 0) {
  265.         return(1);
  266.       }
  267.       anywhere = TRUE;
  268.       strcpy(pattern, shift_lower(alt_pattern));
  269.     }
  270.     else if (strlen(pattern) == 0) {
  271.       return(0);
  272.     }
  273.     else {
  274.       strcpy(pattern, shift_lower(pattern));
  275.     }
  276.  
  277.     if (inalias) {
  278.       for (i = current; i < message_count; i++) {
  279.         matched = name_matches(i, pattern) || alias_matches(i, pattern);
  280.         if (! matched && anywhere) {    /* Look only if no match yet */
  281.           matched = comment_matches(i, pattern) ||
  282.             address_matches(i, pattern);
  283.         }
  284.         if (matched) {
  285.           if (!selected || (selected && aliases[i]->status & VISIBLE)) {
  286.             current = ++i;
  287.             return(1);
  288.           }
  289.         }
  290.       }
  291.     }
  292.     else {
  293.       if (anywhere) {
  294.           return(match_in_message(pattern));
  295.       }
  296.       else {
  297.         for (i = current; i < message_count; i++) {
  298.           if (from_matches(i, pattern) || subject_matches(i, pattern)) {
  299.             if (!selected || (selected && headers[i]->status & VISIBLE)) {
  300.               current = ++i;
  301.               return(1);
  302.             }
  303.           }
  304.         }
  305.       }
  306.     }
  307.  
  308.     return(0);
  309. }
  310.  
  311. int
  312. from_matches(message_number, pat)
  313. int message_number;
  314. char *pat;
  315. {
  316.     /** Returns true iff the pattern occurs in it's entirety
  317.         in the from line of the indicated message **/
  318.  
  319.     return( in_string(shift_lower(headers[message_number]->from), 
  320.         pat) );
  321. }
  322.  
  323. int
  324. subject_matches(message_number, pat)
  325. int message_number;
  326. char *pat;
  327. {
  328.     /** Returns true iff the pattern occurs in it's entirety
  329.         in the subject line of the indicated message **/
  330.  
  331.     return( in_string(shift_lower(headers[message_number]->subject), 
  332.         pat) );
  333. }
  334.  
  335. int
  336. name_matches(message_number, pat)
  337. int message_number;
  338. char *pat;
  339. {
  340.     /** Returns true iff the pattern occurs in it's entirety
  341.         in the proper name of the indicated alias **/
  342.  
  343.     return( in_string(shift_lower(aliases[message_number]->name),
  344.         pat) );
  345. }
  346.  
  347. int
  348. alias_matches(message_number, pat)
  349. int message_number;
  350. char *pat;
  351. {
  352.     /** Returns true iff the pattern occurs in it's entirety
  353.         in the alias name of the indicated alias **/
  354.  
  355.     return( in_string(shift_lower(aliases[message_number]->alias),
  356.         pat) );
  357. }
  358.  
  359. int
  360. comment_matches(message_number, pat)
  361. int message_number;
  362. char *pat;
  363. {
  364.     /** Returns true iff the pattern occurs in it's entirety
  365.         in the comment field of the indicated alias **/
  366.  
  367.     return( in_string(shift_lower(aliases[message_number]->comment),
  368.         pat) );
  369. }
  370.  
  371. int
  372. address_matches(message_number, pat)
  373. int message_number;
  374. char *pat;
  375. {
  376.  
  377.     char *get_alias_address();
  378.     int dummy;
  379.  
  380.     /** Returns true iff the pattern occurs in it's entirety
  381.         in the fully expanded address of the indicated alias **/
  382.  
  383.     return( in_string(shift_lower(
  384.         get_alias_address(aliases[message_number]->alias,TRUE,&dummy)),
  385.         pat) );
  386. }
  387.  
  388. match_in_message(pat)
  389. char *pat;
  390. {
  391.     /** Match a string INSIDE a message...starting at the current 
  392.         message read each line and try to find the pattern.  As
  393.         soon as we do, set current and leave! 
  394.         Returns 1 if found, 0 if not
  395.     **/
  396.  
  397.     char buffer[LONG_STRING];
  398.     int  message_number, lines, line, line_len, err;
  399.  
  400.     message_number = current-1;
  401.  
  402.     error(catgets(elm_msg_cat, ElmSet, ElmSearchingFolderPattern,
  403.         "Searching folder for pattern..."));
  404.  
  405.     while (message_number < message_count) {
  406.  
  407.       if (fseek(mailfile, headers[message_number]->offset, 0L) == -1) {
  408.  
  409.         err = errno;
  410.         dprint(1, (debugfile,
  411.         "Error: seek %ld bytes into file failed. errno %d (%s)\n",
  412.         headers[message_number]->offset, err, 
  413.         "match_in_message"));
  414.         error2(catgets(elm_msg_cat, ElmSet, ElmMatchSeekFailed,
  415.            "ELM [match] failed looking %ld bytes into file (%s)."),
  416.            headers[message_number]->offset, error_description(err));
  417.         return(1);    /* fake it out to avoid replacing error message */
  418.       }
  419.  
  420.       line = 0;
  421.       lines = headers[message_number]->lines;
  422.  
  423.       while ((line_len = mail_gets(buffer, LONG_STRING, mailfile)) && line < lines) {
  424.     
  425.         if(buffer[line_len - 1] == '\n') line++;
  426.  
  427.         if (in_string(shift_lower(buffer), pat)) {
  428.           current = message_number+1; 
  429.           clear_error();
  430.           return(1);
  431.         }
  432.       }
  433.  
  434.       /** now we've passed the end of THIS message...increment and 
  435.           continue the search with the next message! **/
  436.  
  437.       message_number++;
  438.     }
  439.  
  440.     return(0);
  441. }
  442.